package zcj.stu;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.ModelFactory;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.*;

import java.lang.reflect.Method;
import java.util.List;

public class C25 {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
        MockHttpServletRequest request = new MockHttpServletRequest();

        /*处理方法上的@ModelAttribute*/
        RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
        adapter.setApplicationContext(context);
        adapter.afterPropertiesSet();


        request.setParameter("name","张三");
        request.setParameter("age","18");
        ServletInvocableHandlerMethod invocableHandlerMethod = new
                ServletInvocableHandlerMethod(new WebConfig.Controller1(),
                WebConfig.Controller1.class.getMethod("foo", WebConfig.User.class)
        );
        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(null, null);
        invocableHandlerMethod.setDataBinderFactory(binderFactory);
        invocableHandlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
        invocableHandlerMethod.setHandlerMethodArgumentResolvers(getComposite(context.getBeanFactory()));
        ModelAndViewContainer container = new ModelAndViewContainer();

        Method modelFactory = RequestMappingHandlerAdapter.class.getDeclaredMethod("getModelFactory", HandlerMethod.class, WebDataBinderFactory.class);
        modelFactory.setAccessible(true);
        ModelFactory invoke = (ModelFactory) modelFactory.invoke(adapter, invocableHandlerMethod, binderFactory);
        invoke.initModel(new ServletWebRequest(request),container,invocableHandlerMethod);

        invocableHandlerMethod.invokeAndHandle(new ServletWebRequest(request),container);
        MethodParameter[] parameters = invocableHandlerMethod.getMethodParameters();
        for (MethodParameter parameter : parameters) {
            System.out.println(parameter.getParameterName());
        }
        context.close();
        ModelMap model = container.getModel();
        System.out.println(model);
        WebConfig.User user = new WebConfig.User();
        user.setAge(199);
        user.setName("朱传杰");
    }
    public static HandlerMethodArgumentResolverComposite getComposite(ConfigurableBeanFactory beanFactory){

        HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
        composite.addResolvers(
                new RequestParamMethodArgumentResolver(beanFactory,false),
                new PathVariableMethodArgumentResolver(),
                new RequestHeaderMethodArgumentResolver(beanFactory),
                new ServletCookieValueMethodArgumentResolver(beanFactory),
                new ExpressionValueMethodArgumentResolver(beanFactory),
                new ServletRequestMethodArgumentResolver(),
                new ServletModelAttributeMethodProcessor(false),
                new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
                new ServletModelAttributeMethodProcessor(true),
                new RequestParamMethodArgumentResolver(beanFactory,true)
        );
        return  composite;
    }
}
